/* Basic Function */
function abs(x) {
    return x > 0 ? x : -x;
};

function add(a, b) {
    return a + b;
};

function sub(a, b) {
    return a - b;
};

function mul(a, b) {
    return a * b;
};

function div(a, b) {
    return a / b;
};

function rem(a, b) {
    return a % b;
};

function inc(x) {
    return x + 1;
};

function dec(x) {
    return x - 1;
};

function equal(a, b) {
    return a == b;
};

function great(a, b) {
    return a > b;
};

function less(a, b) {
    return a < b;
};

function even(x) {
    return x & 1 == 0;
};

function isExist(o) {
    return (o == undefined || o == null) ? false : true;
}

function empty(o) {
    if (!isExist(o)) return true;
    if (typeof(o) == "object") {
        var hasProp = false;
        for (var prop in o) {
            hasProp = true;
            break;
        }
        return !hasProp ? true : false;
    }
    if (typeof(o) == "array")
        return o.length == 0 ? true : false;
    if (typeof(o) == "string")
        return o.length == 0 ? true : false;
    return false;
}

function inArray(value, array) {
    var i = array.length;
    while (i--) {
        if (array[i] === value)
            return true;
    }
    return false;
}

function parseQueryString(url) {
    if (url) {
        url = url.substr(url.indexOf("?") + 1);
    }
    var result = {},
        queryString = url || location.search.substring(1),
        re = /([^&=]+)=([^&]*)/g,
        m;
    while (m = re.exec(queryString)) {
        result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
    }
    return result;
}

/* Intermediate Function */
function sqrt(x) {
    return Math.sqrt(x);
};

function pow(x, y) {
    return Math.pow(x, y);
};

function factorial(n) {
    if (equal(n, 1)) {
        return 1;
    } else {
        return mul(n, factorial(dec(n)));
    }
};
/* Senior Function */
var binaryCall = function(f, a, b) {
    return f(a, b);
};

var compose = function() {
    var fns = arguments,
        length = arguments.length;
    return function() {
        var i = length;
        while (--i >= 0) {
            arguments = [fns[i].apply(this, arguments)];
        };
        return arguments[0];
    };
};

var sequence = function() {
    var fns = arguments,
        length = arguments.length;
    return function() {
        var i = length;
        while (++i < length) {
            arguments = [fns[i].apply(this.arguments)];
        }
        return arguments[0];
    }
};
/* ProtoType Function*/
var toArray = function(args) {
    return Array.prototype.slice.call(args);
};
var demethodize = function(fn) {
    return function() {
        var args = [].slice.call(arguments, 1);
        return fn.apply(arguments[0], args);
    }
};
var split = demethodize(String.prototype.split);
var slice = demethodize(String.prototype.slice);
var indexOfStr = demethodize(String.prototype.indexOf);
var toLowerCase = demethodize(String.prototype.toLowerCase);
var join = demethodize(Array.prototype.join);
var forEach = demethodize(Array.prototype.forEach);
var map = demethodize(Array.prototype.map);
/* Funtional Funtion */
var logWrapper = function(f) {
    return function() {
        console.log('calling "' + f, name + '"', arguments);
        return f.apply(this, arguments);
    };
};
var sub_curry = function(fn) {
    var args = [].slice.call(arguments, 1);
    console.log(args);
    return function() {
        return fn.apply(this, args.concat(toArray(arguments)));
    };
};
var _ = {};
var curry = function(fn, length, args, holes) {
    length = length || fn.length;
    args = args || [];
    holes = holes || [];
    return function() {
        var _args = args.slice(0),
            _holes = holes.slice(0),
            argStart = _args.length,
            holeStart = _holes.length,
            arg, i;
        for (i = 0; i < arguments.length; i++) {
            arg = arguments[i];
            if (arg === _ && holeStart) {
                holeStart--;
                _holes.push(_holes.shift());
            } else if (arg === _) {
                _holes.push(argStart + i);
            } else if (holeStart) {
                holeStart--;
                _args.splice(_holes.shift(), 0, arg);
            } else {
                _args.push(arg);
            }
        }
        if (_args.length < length) {
            return curry.call(this, fn, length, _args, _holes);
        } else {
            return fn.apply(this, _args);
        }
    }
};
// var processLine = compose(map(trim), split(","));
// var parseCSV = compose(map(processLine), split("\n"));
// function fixedPoint(fx, first) {
//     var tolerance = 0.00001;

//     function closeEnough(x, y) {
//         return less(abs(sub(x, y)), tolerance)
//     };

//     function Try(guess) {
//         var next = fx(guess);
//         if (closeEnough(guess, next)) {
//             return next;
//         } else {
//             return Try(next);
//         }
//     };
//     return Try(first);
// };

// function sqrt(x) {
//     return fixedPoint(
//         function(y) {
//             return function(a, b) {
//                 console.log(a,b);
//                 return div(add(a, b), 2);
//             }(y, div(x, y));
//         },
//         1.0);
// };
// console.log(sqrt(102));
